package com.tyut.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tyut.entity.Files;
import com.tyut.mapper.FilesMapper;
import com.tyut.service.FilesService;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.errors.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.utils.FileNameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * <p>
 * 文件数据表 服务实现类
 * </p>
 *
 * @author 李嘉昕
 * @since 2025-03-18
 */

@Service
public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements FilesService {
    @Value("${lijiaxin.minio.endpoint}")
    private String endpoint;

    @Value("${lijiaxin.minio.username}")
    private String username;

    @Value("${lijiaxin.minio.password}")
    private String password;


    @Override
    public Files getFiles(String md5, Long size, String type) {
        QueryWrapper<Files> wrapper = new QueryWrapper<>();
        wrapper.eq("md5", md5)
                .eq("size", size)
                .eq("type", type);
        return this.getOne(wrapper);
    }

    public void checkFiles(MinioClient client , String bucket ,Long count, String oldPath) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 旧文件存在并且只有自己引用，则可以删除旧文件
        if (!Objects.equals(oldPath, "default") && count <= 1) {

            String oldFilename = oldPath.substring(("/" + bucket + "/").length());

            System.out.println(oldFilename);

            RemoveObjectArgs removeArgs = RemoveObjectArgs.builder()
                    .bucket(bucket)
                    .object(oldFilename)
                    .build();

            client.removeObject(removeArgs);


            QueryWrapper<Files> wrapper = new QueryWrapper<>();
            wrapper.eq("path", oldPath);
            // 删除旧文件记录
            this.remove(wrapper);
        }
    }

    @Override
    public String fileUpload(String bucket, MultipartFile file, Long count, String oldPath) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 创建客户端
        MinioClient client = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(username, password)
                .build();

        // 获取到文件md5 大小 类型
        String md5 = DigestUtils.md5Hex(file.getInputStream());
        Long size = file.getSize();
        String type = file.getContentType();

        // 判断是否已经上传过该文件
        Files Files = getFiles(md5, size, type);
        if (null != Files) {
            // 检查旧文件是否可以被删除
            checkFiles(client, bucket, count, oldPath);

            return Files.getPath();
        }

        // 如果没有上传过，则进行文件上传操作
        // 文件重命名
        StringBuilder name = new StringBuilder();
        name.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")))
                .append(RandomStringUtils.random(6, false, true)) // 随机生成6位数字
                .append(".")
                .append(FileNameUtils.getExtension(file.getOriginalFilename()));


        // 创建上传参数
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(bucket)
                .object(name.toString())
                .stream(file.getInputStream(), size, -1) // 设置文件流和大小，-1表示不限制速率
                .contentType(file.getContentType())
                .build();

        // 执行上传
        client.putObject(args);

        // 得到文件路径
        String path = "/" + bucket + "/" + name.toString();

        // 将改写后的文件记录保存到数据库
        Files = new Files(
                md5,
                size,
                type,
                path
        );

        // 保存到数据库
        this.save(Files);


        // 判断旧文件是否为默认路径
        checkFiles(client, bucket, count, oldPath);

        return path;
    }
}
